package com.dlyk.filter;

import com.dlyk.bean.TUser;
import com.dlyk.constant.Constants;
import com.dlyk.result.CodeEnum;
import com.dlyk.result.R;
import com.dlyk.service.RedisService;
import com.dlyk.utils.JSONUtils;
import com.dlyk.utils.JWTUtils;
import com.dlyk.utils.ResponseUtils;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


@Component
public class TokenVerifyFilter extends OncePerRequestFilter {

    @Autowired
    private RedisService redisService;

    // SpringBoot框架的IOC容器线程池
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 如果是登录请求，此时还没有生成JWT，那不需要对登录请求进行jwt验证
        if (request.getRequestURI().equals(Constants.LOGIN_URI)){
            filterChain.doFilter(request,response);
        } else {


            String token=null;
            if (request.getRequestURI().equals(Constants.EXPORT_EXCEL_URI)){
                token=request.getParameter(Constants.TOKEN_NAME);
            }else {
                token=request.getHeader(Constants.TOKEN_NAME);
            }

            if (!StringUtils.hasText(token)){
                // Token验证未通过的统一结果
                R result = R.FAIL(CodeEnum.TOKEN_IS_EMPTY);
                // 把R对象转换成json
                String resultJSON = JSONUtils.toJSON(result);
                // 把R以json返回给前端
                ResponseUtils.write(response,resultJSON);
                return;
            }

            // token信息被篡改
            if (!JWTUtils.verifyJWT(token)){
                // 验证Token失败的统一结果
                R result = R.FAIL(CodeEnum.TOKEN_IS_ERROR);
                // 把R对象转出json
                String resultJSON = JSONUtils.toJSON(result);
                // 把R对象以json返回给前端
                ResponseUtils.write(response,resultJSON);
                return;
            }

            TUser tUser = JWTUtils.parseUserFromJWT(token);
            String redisToken = (String) redisService.getValue(Constants.REDIS_JWT_KEY + tUser.getId());

            if (!StringUtils.hasText(redisToken)){
                //Token验证未通过的统一结果
                R result = R.FAIL(CodeEnum.TOKEN_IS_EXPIRED);
                // 把R对象转出json
                String resultJson = JSONUtils.toJSON(result);
                // 把R对象以json返回给前端
                ResponseUtils.write(response,resultJson);
                return;
            }

            if (!token.equals(redisToken)){
                // Token验证未通过的统一结果
                R result = R.FAIL(CodeEnum.TOKEN_IS_ERROR);
                // 把R对象转出json
                String resultJson = JSONUtils.toJSON(result);
                // 把R对象以json返回给前端
                ResponseUtils.write(response,resultJson);
                return;
            }

            //jwt验证通过了，那么在spring security的上下文环境中要设置一下，设置当前这个人是登录过的，你后续不要再拦截他了
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(tUser, tUser.getLoginPwd(), tUser.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);

            // 使用SpringBoot的线程池来刷新Token
            threadPoolTaskExecutor.execute(()->{
                String rememberMe = request.getHeader("rememberMe");
                if (Boolean.parseBoolean(rememberMe)){
                    redisService.expire(Constants.REDIS_JWT_KEY+tUser.getId(),Constants.EXPIRE_TIME, TimeUnit.SECONDS);
                }else {
                    redisService.expire(Constants.REDIS_JWT_KEY+tUser.getId(),Constants.DEFAULT_EXPIRE_TIME,TimeUnit.SECONDS);
                }
            });

            // 验证jwt通过，让Filter链继续执行
            filterChain.doFilter(request,response);
        }
    }
}
